/**
 * 
 */
package info.niwota.frames.net;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

import android.os.Environment;

/**
 * @author qiangli
 * 
 */
public class FileWrap implements Wrap, Serializable {

	private static final long serialVersionUID = VERSION;

	public static final int BUFSIZE = 8192;
	
	public static final File TOP = new File(Environment.getExternalStorageDirectory(), "info.niwota.frames/net/images");;

	static {
		if (!TOP.exists()) {
			TOP.mkdirs();
		}
	}
	
	private static long seq = System.currentTimeMillis();

	private static File createTempFile() {
		File f = new File(TOP, nextName());
		while(f.exists()) {
			f = new File(TOP, nextName());
		}
		return f;
	}

	synchronized private static String nextName() {
		seq++;
		return "" + seq;
	}

	private transient File file;

	private transient File data;

	private transient String name;

	private transient String path;

	private transient long length;

	private transient long lastModified;

	private transient boolean canRead;

	private transient boolean canWrite;

	private transient boolean isDirectory;

	private transient boolean isFile;

	public FileWrap() {
	}

	public FileWrap(File file) {
		this.file = file;
		//
		name = file.getName();
		path = file.getPath();
		length = file.length();
		lastModified = file.lastModified();
		canRead = file.canRead();
		canWrite = file.canWrite();
		isDirectory = file.isDirectory();
		isFile = file.isFile();
	}

	public File getData() {
		return data;
	}

	public String getName() {
		return name;
	}

	public String getPath() {
		return path;
	}

	private void writeObject(ObjectOutputStream out) throws IOException {
		out.writeLong(VERSION);
		//
		out.writeObject(name);
		out.writeObject(path);
		out.writeLong(length);
		out.writeLong(lastModified);
		out.writeBoolean(canRead);
		out.writeBoolean(canWrite);
		out.writeBoolean(isDirectory);
		out.writeBoolean(isFile);
		
		if (isFile) {
			FileInputStream is = new FileInputStream(file);
			out.flush();
			copy(is, out, (int) length);
			is.close();
		}
	}

	private void readObject(ObjectInputStream in) throws IOException,
			ClassNotFoundException {
		in.readLong();
		//
		name = (String) in.readObject();
		path = (String) in.readObject();
		
		length = in.readLong();
		lastModified = in.readLong();
		canRead = in.readBoolean();
		canWrite = in.readBoolean();
		isDirectory = in.readBoolean();
		isFile = in.readBoolean();

		if (isFile) {
			data = createTempFile();
			//
			FileOutputStream os = new FileOutputStream(data);
			copy(in, os, (int) length);
			os.close();
			//
			if (length != data.length()) {
				throw new IOException("File corrupted");
			}
			data.setLastModified(lastModified);
			if (canRead && !canWrite) {
				data.setReadOnly();
			}
		}
	}

	@Override
	public String toString() {
		return "FileWrap [file=" + file + ", data=" + data + ", name=" + name
				+ ", path=" + path + ", length=" + length + ", lastModified="
				+ lastModified + ", canRead=" + canRead + ", canWrite="
				+ canWrite + ", isDirectory=" + isDirectory + ", isFile="
				+ isFile + "]";
	}
	

	public static void copy(InputStream is, OutputStream os) throws IOException {
		byte[] buf = new byte[BUFSIZE];
		while (true) {
			int read = is.read(buf);
			if (read == -1) {
				break;
			}
			if (read > 0) {
				os.write(buf, 0, read);
			}
		}
		os.flush();
	}

	public static void copy(final InputStream is, final OutputStream os, final int len)
			throws IOException {
		byte[] buf = new byte[BUFSIZE];
		for (int i = 0; i < len;) {
			int read = is.read(buf, 0, Math.min(buf.length, len));
			if (read == -1) {
				break;
			}
			if (read > 0) {
				i += read;
				os.write(buf, 0, read);
			}
		}
		os.flush();
	}

}
